{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The `Bool` Widgets\n",
    "\n",
    "+ CheckBox\n",
    "+ ToggleButton"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These widgets can be used to represent a Boolean value. The idea is pretty simple, the widget can be in one of two states which represent the two boolean values.\n",
    "\n",
    "    Checked / On : True\n",
    "    Unchecked / Off : False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "{-# LANGUAGE OverloadedStrings #-}\n",
    "{-# LANGUAGE FlexibleContexts #-}\n",
    "import IHaskell.Display.Widgets\n",
    "import Data.Text (pack, unpack)\n",
    "import Text.Printf (printf)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Simple demonstration"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "-- Check box\n",
    "chk <- mkCheckBox\n",
    "\n",
    "-- Toggle button\n",
    "tgb <- mkToggleButton\n",
    "\n",
    "-- Valid widget: Displaying booleans conveniently\n",
    "vld <- mkValidWidget"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Below, we represent one boolean using a checkbox, and the other using a toggle button. The logical and (`&&`) of the two is displayed below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "-- Display the widgets\n",
    "chk\n",
    "tgb\n",
    "vld"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `BoolValue` field represents the underlying boolean value."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "setField chk Description \"Bool 1: \"\n",
    "setField tgb Description \"Bool 2\"\n",
    "\n",
    " -- Cosmetic changes\n",
    "setField vld Description \"Bool 1 && Bool 2\"\n",
    "\n",
    " -- And (&&) the two values, and send output to html widget\n",
    "setHandler w = setField w ChangeHandler $ do\n",
    "  b1 <- getField chk BoolValue\n",
    "  b2 <- getField tgb BoolValue\n",
    "  setField vld BoolValue (b1 && b2)\n",
    "\n",
    "setHandler chk\n",
    "setHandler tgb"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Extended example"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's try to create a graphical 8-bit-binary to decimal converter. We'll represent seven bits using `ToggleButton` widgets, and the negative bit using a `CheckBox`. The binary number is represented using 1+7-bit sign-and-magnitude representation for simplicity.\n",
    "\n",
    "Boxes are used to layout the widgets in an appealing manner, and the output widget is used to display the result."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "-- First, some library functions\n",
    "import Control.Monad (replicateM, forM_)\n",
    "import Data.IORef\n",
    "import IHaskell.Display (plain)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we create a `CheckBox` and seven `ToggleButton`s."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "sign <- mkCheckBox\n",
    "bits <- replicateM 7 mkToggleButton\n",
    "\n",
    "setField sign Description \"Negative\"\n",
    "forM_ bits $ \\t -> do\n",
    "  setField t ButtonStyle PrimaryButton\n",
    "  setField t BorderRadius 20"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then we create a `FlexBox` to hold the widgets, and an `HTMLWidget` to display the output."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "box <- mkFlexBox\n",
    "out <- mkHTMLWidget\n",
    "\n",
    "-- Sub-containers\n",
    "box1 <- mkFlexBox\n",
    "setField box1 Children [ChildWidget sign, ChildWidget out]\n",
    "box2 <- mkFlexBox\n",
    "setField box2 Children (map ChildWidget $ reverse bits)\n",
    "\n",
    "-- Add widgets to the container\n",
    "setField box Children (map ChildWidget [box1, box2])\n",
    "setField box Orientation VerticalOrientation\n",
    "\n",
    "-- Add some UI chrome\n",
    "setField box BoxStyle InfoBox\n",
    "setField box BorderRadius 20\n",
    "setField out BorderStyle GrooveBorder\n",
    "setField out BorderRadius 20\n",
    "setField out BorderWidth 4\n",
    "setField out Width 100\n",
    "setField out Height 30\n",
    "setField out Margin 10\n",
    "setField sign Padding 10\n",
    "setField box2 Padding 10\n",
    "setField box2 Pack BaselineLocation\n",
    "\n",
    "-- Display the container\n",
    "box"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, we implement the logic of our converter, and make it send the output to the `HTMLWidget` we created above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import Control.Arrow (first, second)\n",
    "\n",
    "-- Mutable value, with a sign bit\n",
    "val <- newIORef (0 :: Int, False)\n",
    "\n",
    "-- Helper function to redraw output\n",
    "refresh :: (Int, Bool) -> IO ()\n",
    "refresh (x, b) = \n",
    "  let val = x * if b then (-1) else 1\n",
    "      fmt = \"<div align=\\\"center\\\"><b>%d</b></div>\"\n",
    "  in setField out StringValue (pack $ printf fmt val)\n",
    "\n",
    "setField sign ChangeHandler $ do\n",
    "  -- Change sign for value\n",
    "  modifyIORef val (second not)\n",
    "  -- Redraw output\n",
    "  readIORef val >>= refresh\n",
    "\n",
    "forM_ (zip bits (iterate (*2) 1)) $ \\(t, n) -> do\n",
    "  setField t Description \"0\"\n",
    "  setField t ChangeHandler $ do\n",
    "    f <- getField t BoolValue\n",
    "    setField t Description (if f then \"1\" else \"0\")\n",
    "    modifyIORef val (first $ if f then (+n) else (\\x->x-n))\n",
    "    readIORef val >>= refresh"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Haskell",
   "language": "haskell",
   "name": "haskell"
  },
  "language_info": {
   "codemirror_mode": "ihaskell",
   "file_extension": ".hs",
   "name": "haskell",
   "version": "7.10.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
